package net.icapsid.counter.client;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import net.icapsid.counter.client.util.math.FloatMatrix;
import net.icapsid.counter.client.util.math.MatrixUtil;

import com.google.gwt.core.client.GWT;
import com.googlecode.gwtgl.binding.WebGLRenderingContext;
import com.googlecode.gwtgl.binding.WebGLUniformLocation;

public class FlightControl {

	private long lastTime;
	private float ambientColor[][];

	List<Projectile> objs = new LinkedList<Projectile>();

	public FlightControl(float color[][]) {
		ambientColor = color;
	}

	void draw(WebGLRenderingContext glContext, int points,
			WebGLUniformLocation projectionMatrixUniform,
			FloatMatrix perspectiveMatrix,
			WebGLUniformLocation ambientColorUniform) {

		FloatMatrix translationMatrix;
		FloatMatrix resultingMatrix;

		for (Projectile p : objs) {
			float xyz[] = p.getPosition();

			translationMatrix = MatrixUtil.createTranslationMatrix(xyz[0],
					xyz[1], xyz[2]);

			resultingMatrix = perspectiveMatrix.multiply(translationMatrix);// .multiply(rotationMatrix);

			glContext.uniformMatrix4fv(projectionMatrixUniform, false,
					resultingMatrix.getColumnWiseFlatData());

			int colorIndex = 0;
			int i = p.getIndex();

			if (i > 2) {
				colorIndex = (i - 1) / 2;
			}

			glContext.uniform3f(ambientColorUniform,
					ambientColor[colorIndex][0], ambientColor[colorIndex][1],
					ambientColor[colorIndex][2]);
			glContext.drawArrays(WebGLRenderingContext.TRIANGLES, 0, points);

		}
	}

	void launchFrom(float x, float y, float z, int i) {
		Projectile p = new Projectile(i, x, y, z);
		
		double phi = (Math.random() - 0.5) * Math.PI/16.0f;
		double theta = (Math.random() - 0.5) * Math.PI/16.0f;

		float v[] = new float[3];
		
		float v_not = 1.0f + (float) (Math.random() - 0.5f) / 2.0f;
		
		v[0] = (float) (v_not * Math.sin(theta) * Math.cos(phi));
		v[1] = (float) (v_not * Math.sin(theta) * Math.sin(phi));
		v[2] = (float) (v_not * Math.cos(theta));
		
		p.setVelocity(v);
		objs.add(p);
	}

	void updatePhysics() {

		long lifetime = 10000;

		long currentTime = System.currentTimeMillis();

		long elapsedTime = (currentTime - lastTime);
		
		// HACK!
		if(lastTime == 0){
			elapsedTime = 101;
		}

		if (elapsedTime < 100) {
			return;
		}
		
		float dt = 0.25f * elapsedTime / 100f;
		float a[] = new float[]{0f, 0f, 1.0f};

		for (int i = 0; i < objs.size(); ++i) {

			Projectile p = objs.get(i);

			if ((currentTime - p.getSpawnTime()) > lifetime) {
				objs.remove(i);
				
				if(i >= objs.size())
					continue;
				
				p = objs.get(i);
			}

			float r[] = p.getPosition();
			float v[] = p.getVelocity();
			
			for(int k = 0; k < 3; ++k){
				r[k] = r[k] + v[k] * dt + 0.5f * a[k] * dt * dt;
				v[k] = v[k] + a[k] * dt;
			}

			p.setPosition(r);
			p.setVelocity(v);
		}
		lastTime = currentTime;
	}
}

class Projectile {

	float r[] = new float[3];
	float v[] = new float[3];
	float a[] = new float[3];

	long spawnTime = System.currentTimeMillis();
	int index;

	public Projectile(int i, float x, float y, float z) {
		index = i;
		r[0] = x;
		r[1] = y;
		r[2] = z;
	}

	int getIndex() {
		return index;
	}

	float[] getPosition() {
		return r;
	}

	long getSpawnTime() {
		return spawnTime;
	}

	void setPosition(float[] xyz) {
		r = xyz;
	}
	
	void setVelocity(float x, float y, float z) {
		v[0] = x;
		v[1] = y;
		v[2] = z;
	}
	void setVelocity(float[] xyz) {
		v = xyz;
	}
	float[] getVelocity() {
		return v;
	}
}
